// INCLUDE FILES 
#include "SmsSocketReader.h"            // CSmsSocketReader
#include "SmsSocketReaderObserver.h"    // MSmsSocketReaderObserver

#include <smsuaddr.h>                   // TSmsAddr
#include <gsmubuf.h>                    // CSmsBuffer
#include <smsustrm.h>                   // RSmsSocketReadStream
#include <gsmumsg.h>                    // CSmsMessage
    
// ---------------------------------------------------------------------------
// CSmsSocketReader::CSmsSocketReader()
// Default C++ constructor.
// ---------------------------------------------------------------------------
//
CSmsSocketReader::CSmsSocketReader( MSmsSocketReaderObserver& aObserver ) 
    : CActive( EPriorityStandard ), iObserver( aObserver )
    {
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::~CSmsSocketReader()
// Destructor.
// ---------------------------------------------------------------------------
//
CSmsSocketReader::~CSmsSocketReader()
    {
    // cancel any request, if outstanding
    Cancel();
    
    iReadSocket.Close();
    iFs.Close();
    iSocketServ.Close();
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::NewL()
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CSmsSocketReader* CSmsSocketReader::NewL( MSmsSocketReaderObserver& aObserver )
    {
    CSmsSocketReader* self = CSmsSocketReader::NewLC( aObserver );
    CleanupStack::Pop( self );
    return self;
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::NewLC()
// Two-phased constructor.
// ---------------------------------------------------------------------------
//
CSmsSocketReader* CSmsSocketReader::NewLC( MSmsSocketReaderObserver& aObserver )
    {
    CSmsSocketReader* self = new ( ELeave ) CSmsSocketReader( aObserver );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::ConstructL()
// Default EPOC constructor.
// ---------------------------------------------------------------------------
//
void CSmsSocketReader::ConstructL()
    {
    CActiveScheduler::Add( this );
    
    User::LeaveIfError( iSocketServ.Connect() );
    User::LeaveIfError( iFs.Connect() );
    
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::DoCancel()
// Implements cancellation of an outstanding request.
// ---------------------------------------------------------------------------
//
void CSmsSocketReader::DoCancel()
    {
    iReadSocket.CancelIoctl();
    iState = ESmsIdle;
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::RunL()
// Handles an active objects request completion event.
// ---------------------------------------------------------------------------
//
void CSmsSocketReader::RunL()
    {
	RDebug::Print(_L("LOG: CSmsSocketReader::RunL"));	
    if ( iStatus == KErrNone )
        {
        if ( iState == ESmsListening )
            {
            // allocate SMS buffer
            CSmsBuffer* buffer = CSmsBuffer::NewL();
            CleanupStack::PushL( buffer );

            // create new incoming message, pass ownership of the buffer!
            CSmsMessage* message = CSmsMessage::NewL( iFs, 
                    CSmsPDU::ESmsDeliver, buffer );
            CleanupStack::Pop( buffer );
            CleanupStack::PushL( message );

            // open socket read stream
            RSmsSocketReadStream readStream( iReadSocket );
            CleanupClosePushL( readStream );

            // read message
            message->InternalizeL( readStream );
            CleanupStack::PopAndDestroy( &readStream );

            // extract the message body
            HBufC* body = HBufC::NewLC( message->Buffer().Length() );
            TPtr bodyPtr( body->Des() );
            message->Buffer().Extract( bodyPtr, 0, message->Buffer().Length() );
        		
            iObserver.MessageReceivedL(*body, message->ToFromAddress() );
            CleanupStack::PopAndDestroy( 2, message ); // body, message

            // notify system about successful receiving
            iReadSocket.Ioctl( KIoctlReadMessageSucceeded, iStatus, 
                    NULL, KSolSmsProv );
            iState = ESmsSystemNotyfing;
            SetActive();
            }
        else
            {
            Start();
            }
        }
    else
        {
        iObserver.HandleErrorL( iStatus.Int() );
        }
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::RunError()
// Handles a leave occurring in the request completion event handler RunL().
// ---------------------------------------------------------------------------
//
TInt CSmsSocketReader::RunError( TInt aError )
    {
    TRAP_IGNORE( iObserver.HandleErrorL( aError ) );
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::Start()
// Starts waiting for the actual socket data.
// ---------------------------------------------------------------------------
//
void CSmsSocketReader::Start()
    {
	RDebug::Print(_L("LOG: CSmsSocketReader::Start"));		
    // wait for an incoming data
    iReadSocket.Ioctl( KIOctlSelect, iStatus, &iBuf, KSOLSocket );
    iState = ESmsListening;
    SetActive();
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::StartListeningL()
// Starts listening for an incoming SMS.
// ---------------------------------------------------------------------------
//
void CSmsSocketReader::StartListeningL( const TDesC8& aMatchTag )
    {
    // we can't handle several requests simultaneously
    if ( IsActive() )
        {
        // stop any request
        StopListening();
        }

    // just in case
    iReadSocket.Close();
    
    // open read socket
    User::LeaveIfError( iReadSocket.Open( iSocketServ,
            KSMSAddrFamily, KSockDatagram, KSMSDatagramProtocol ) );

    // set match pattern
    TSmsAddr smsAddr; 
    smsAddr.SetSmsAddrFamily( ESmsAddrMatchText ); 
    smsAddr.SetTextMatch( aMatchTag );
    
    // use this to read the message from a certain port
    //smsAddr.SetSmsAddrFamily( ESmsAddrApplication8BitPort );
    //smsAddr.SetPort( 16500 ); // GSM Application port from 16000 to 16999
    
    // bind the socket
    User::LeaveIfError( iReadSocket.Bind( smsAddr ) );
    iBuf() = KSockSelectRead;
    
    Start();
    }

// ---------------------------------------------------------------------------
// CSmsSocketReader::StopListening()
// Stops listening.
// ---------------------------------------------------------------------------
//
void CSmsSocketReader::StopListening()
    {
    Cancel();
    
    iReadSocket.Close();
    }
